package com.project.springboot.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gitee.yongzhuzl.commonutil.util.date.CalendarUtil;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.project.springboot.entity.Student;
import com.project.springboot.mapper.StudentMapper;
import com.project.springboot.service.StudentService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.net.URLEncoder;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 学生表(Student)表服务实现类
 * @author 朱正磊
 * @since 2023-08-16 00:00:20
 */
@Slf4j
@Service("studentService")
@Transactional
public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student> implements StudentService {

    @Resource
    private ThreadPoolExecutor threadPoolExecutor;

    @Override
    public List<Student> getStudentList() {
        Long startTime = CalendarUtil.getStartTime();
        LambdaQueryWrapper<Student> wrapper = new LambdaQueryWrapper<>();
        wrapper.last("limit 1000");
        List<Student> list = this.list(wrapper);
        Long interval = CalendarUtil.interval(startTime);
        log.info("耗时 = {}秒", interval);
        log.info("学生数量 = {}", list.size());
        return list;
    }

    @Override
    public void batchInsert() {
        List<Student> list = new ArrayList<>();
        for (int i = 1; i <= 10000; i++) {
            Student student = new Student();
            student.setName("朱正磊" + i);
            student.setSex(1);
            student.setAge(33);
            student.setAddress("苏州吴江");
            student.setHobby("足球");
            student.setBirthday(CalendarUtil.stringToDate("1990-12-26 00:00:00"));
            list.add(student);
        }
        this.saveBatch(list);
    }

    /**
     * description: 导出Excel（方式二）
     * @author 朱正磊
     * @date 2023-08-31 16:04:37
     * @param response 响应对象
     */
    @Override
    public void exportExcel2(HttpServletResponse response) {
        try {
            List<Student> studentList = this.getStudentList();

            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String fileName = URLEncoder.encode("导出", "UTF-8");
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");

            // 内容样式策略
            WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
            // 垂直居中,水平居中
            contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
            contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
            contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);
            contentWriteCellStyle.setBorderTop(BorderStyle.THIN);
            contentWriteCellStyle.setBorderRight(BorderStyle.THIN);
            contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);
            // 字体策略
            WriteFont contentWriteFont = new WriteFont();
            // 字体大小
            contentWriteFont.setFontHeightInPoints((short) 12);
            contentWriteCellStyle.setWriteFont(contentWriteFont);

            EasyExcel.write(response.getOutputStream(), Student.class)
                    // 设置sheet名称
                    .sheet("学生信息")
                    // 自动匹配列宽
                    .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                    // 设置单元格样式
                    .registerWriteHandler(new HorizontalCellStyleStrategy(null, contentWriteCellStyle))
                    .doWrite(studentList);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * description: 新增一条学生数据
     * @author 朱正磊
     * @date 2024-05-23 13:41:44
     */
    @Override
    public void addStudent() {
        Student student = new Student();
        student.setName("张学友");
        student.setSex(1);
        student.setAge(58);
        student.setAddress("香港九龙");
        student.setHobby("唱歌");
        student.setBirthday(new Date());
        this.save(student);
        throw new RuntimeException("发生未知异常！");
    }

    /**
     * description: 新增一条学生数据
     * @author 朱正磊
     * @date 2025-10-22 09:19:05
     */
    //@Transactional(propagation = Propagation.REQUIRES_NEW)
    @Transactional(propagation = Propagation.NESTED)
    @Override
    public void saveStudent() {
        Student student = new Student();
        student.setName("林家栋");
        student.setSex(1);
        student.setAge(50);
        student.setAddress("香港新界");
        student.setHobby("拍戏");
        student.setBirthday(new Date());
        this.save(student);
        throw new RuntimeException("发生未知运行时异常啦！");
    }

    /**
     * description: 新增一条学生数据
     * @author 朱正磊
     * @date 2025-10-22 09:19:05
     */
    //@Transactional(propagation = Propagation.REQUIRES_NEW)
    @Transactional(propagation = Propagation.NESTED)
    @Override
    public void createStudent() {
        Student student = new Student();
        student.setName("林雪");
        student.setSex(1);
        student.setAge(70);
        student.setAddress("香港旺角");
        student.setHobby("拍戏");
        student.setBirthday(new Date());
        this.save(student);
    }

    /**
     * description: 根据姓名查询学生
     * @author 朱正磊
     * @date 2025-06-21 13:12:34
     * @param name 姓名
     * @return 返回学生
     */
    @Override
    public Student getStudentByName(String name) {

        System.out.println("name = " + name);

        if (true) {
            throw new RuntimeException("发生未知异常！");
        }

        Student student = new Student();
        student.setName(name);
        return student;
    }

    /**
     * description: 根据姓名模糊查询学生集合
     * @author 朱正磊
     * @date 2025-05-13 15:44:48
     * @param name 姓名
     * @return 返回学生集合
     */
    @Override
    public List<Student> testCache(String name) throws ExecutionException {
        Long startTime = CalendarUtil.getStartTime();

        LoadingCache<String, List<Student>> cache = CacheBuilder.newBuilder()
                .maximumSize(10)
                .expireAfterWrite(Duration.ofMinutes(10))
                .recordStats()
                .build(new CacheLoader<String, List<Student>>() {
                    @Override
                    public List<Student> load(String key) {
                        LambdaQueryWrapper<Student> wrapper = Wrappers.lambdaQuery();
                        wrapper.like(Student::getName, key);
                        return baseMapper.selectList(wrapper);
                    }
                });
        List<Student> studentList = cache.get(name);

        Long endTime = CalendarUtil.getStartTime();
        long interval = endTime - startTime;
        System.out.println("根据姓名模糊查询学生集合耗时 = " + interval + "毫秒");

        // 查看统计信息
        System.out.println(cache.stats());

        return studentList;
    }

    /**
     * description: 测试异步线程
     * @author 朱正磊
     * @date 2025-06-04 15:14:55
     * @param id 主键
     * @return 返回学生对象
     */
    @Override
    public Student selectById(Integer id) {
        long start = System.currentTimeMillis();
        Student student = this.getById(id);

        // 异步线程
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            try {
                Thread.sleep(10000);
                Student stu = new Student();
                stu.setName("邓萃雯");
                stu.setSex(2);
                stu.setAge(49);
                stu.setAddress("香港新界");
                stu.setHobby("拍戏");
                stu.setBirthday(new Date());
                this.save(stu);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }, threadPoolExecutor);

        long end = System.currentTimeMillis();
        long interval = end - start;
        System.out.println("耗时 = " + interval + "毫秒");

        // 线程阻塞
        // future.join();

        return student;
    }

    /**
     * description: 测试异步线程
     * @author 朱正磊
     * @date 2025-06-04 15:14:55
     * @return 返回异步任务结果
     */
    @Async
    @Override
    public CompletableFuture<String> insertOne() {
        try {
            Thread.sleep(10000);
            Student stu = new Student();
            stu.setName("萱萱");
            stu.setSex(2);
            stu.setAge(33);
            stu.setAddress("上海");
            stu.setHobby("拍戏");
            stu.setBirthday(new Date());
            this.save(stu);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return CompletableFuture.completedFuture("插入一条学生信息的异步任务完成");
    }

    /**
     * description: 批量保存
     * @author 朱正磊
     * @date 2025-06-11 13:25:29
     */
    @Override
    public void batchSave() {
        List<Student> studentList = Arrays.asList(
                new Student(8, "薛振兴", 1, 30, "苏州", "足球", CalendarUtil.stringToDate("1995-08-08", "yyyy-MM-dd")),
                new Student(9, "黄灿灿", 2, 29, "苏州", "绘画", CalendarUtil.stringToDate("1996-09-08", "yyyy-MM-dd")),
                new Student(10, "贾志浩", 1, 28, "苏州", "游泳", CalendarUtil.stringToDate("1997-04-08", "yyyy-MM-dd")),
                new Student(11, "刘平丽", 2, 27, "苏州", "舞蹈", CalendarUtil.stringToDate("1998-07-08", "yyyy-MM-dd"))
        );
        studentList.forEach(student -> {
            Integer age = student.getAge();
            if (age > 28) {
                return;
            }
            this.save(student);
        });
    }

}
